package com.xc.ezplan.log.aspect;

import cn.dev33.satoken.stp.StpUtil;
import com.xc.ezplan.core.dto.AdminUserDTO;
import com.xc.ezplan.core.utils.WebContextHolder;
import com.xc.ezplan.log.entity.AdminLog;
import com.xc.ezplan.log.service.AdminLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.xc.ezplan.core.utils.StringUtils;
import com.xc.ezplan.core.utils.ThrowableUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author lixingchen
 * @date 2022/11/15
 * @description 打印日志切面
 */
@Component
@Aspect
@Slf4j
@RequiredArgsConstructor
public class LogAspect {

    private final AdminLogService adminLogService;

    /**
     * 保证线程安全
     */
    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.xc.ezplan.log.annotation.Log)")
    public void logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    /**
     * 配置环绕通知,使用在方法logPointcut()上注册的切入点
     *
     * @param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;
        currentTime.set(System.currentTimeMillis());
        result = joinPoint.proceed();
        AdminLog log = new AdminLog("INFO",System.currentTimeMillis() - currentTime.get());
        HttpServletRequest request = WebContextHolder.getHttpServletRequest();
        adminLogService.saveLog(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log);
        currentTime.remove();
        return result;
    }

    /**
     * 配置异常通知
     *
     * @param joinPoint join point for advice
     * @param e exception
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        // currentTime获取的是logAround中set的时间
        AdminLog log = new AdminLog("ERROR",System.currentTimeMillis() - currentTime.get());
        currentTime.remove();
        log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
        HttpServletRequest request = WebContextHolder.getHttpServletRequest();
        adminLogService.saveLog(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log);
    }

    public String getUsername() {
        try {
            AdminUserDTO adminUserDTO = (AdminUserDTO) StpUtil.getSession().get("userInfo");
            return adminUserDTO.getUsername();
        }catch (Exception e){
            return "";
        }
    }
}
